Imports System.Net 'For DNS class
Imports System.Net.Sockets 'For Socket class
Public Class clsSocket
#Region "Variables"
    Private sktThis As New Socket(AddressFamily.InterNetwork, _
        SocketType.Stream, ProtocolType.Tcp)
    Private ep As New IPEndPoint(Dns.Resolve("localhost").AddressList(0) _
        , 30000)
    Private ASCII As New System.Text.ASCIIEncoding
    Private bDebug As Boolean
    Private iConTrys As Int32 = 0
    'This is the array that tells the reconnect how long to wait before
    'the next connection try. It increments up to 30 minutes where it will just
    'proceed at 30 minute increments
    '1st Failed Attempt = Wait 10 seconds
    '2nd Failed Attempt = Wait 1 minute (1*60=60)
    '3rd Failed Attempt = Wait 5 minutes (5*60=300)
    '4th Failed Attempt = Wait 15 minute (15*60=900)
    '5th and 6th Failed Attempts = Wait 30 minutes (30*60=1800)
    'any higher than 6 attempts will shut down the application with an error
    Private iTryIncArr() As Int32 = {10, 60, 300, 900, 1800}
    Private tmrError As Timer
#End Region
#Region "Events"
    Public Event DataReceived(ByVal data As String)
    Public Event DataSent(ByVal data As String)
    Public Event NewVersion(ByVal data As String)
#End Region
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="DEBUG"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	7/12/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Sub New(Optional ByVal DEBUG As Boolean = False)
        bDebug = DEBUG
    End Sub
    'Public Sub New()
    '    'This space intentionally left blank
    '    'Since there is no need for initialization in the
    '    '  regular Constructor, a normal constructor can still
    '    '  be called. If you need debuggin
    'End Sub
#Region "Methods"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jas]	7/12/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Sub Connect()
        If Threading.Thread.CurrentThread.Name Is Nothing Then Threading.Thread.CurrentThread.Name = "clsSocket.Connect"
        If bDebug Then Exit Sub
        sktThis.BeginConnect(ep, AddressOf connectCallback, Nothing)
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="ar"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jas]	7/12/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Private Sub connectCallback(ByVal ar As IAsyncResult)
        If Threading.Thread.CurrentThread.Name Is Nothing Then Threading.Thread.CurrentThread.Name = "clsSocket.connectCallback"
        sktThis.EndConnect(ar)
        Dim bytes(4095) As Byte
        Try
            sktThis.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, _
                AddressOf recvCallback, bytes)
        Catch
            'Need to finish this handler later.
            'needs to be able to restart the main socket from here, but
            'only try every 10 - 30 seconds
            MsgBox("The server has failed to respond. Please try again later.") 'Will try to reconnect in " + iTryIncArr(iConTrys).ToString + " seconds.")
            'tmrError = New Timer
            'AddHandler tmrError.Tick, AddressOf tmrError_Tick
            'Setup timer
            'tmrError.Interval = IIf(iConTrys = 5, iTryIncArr(4), iTryIncArr(iConTrys))
            'tmrError.Enabled = True
            'iConTrys += 1
            Application.Exit()
            'sktThis.Close()
            'Threading.Thread.CurrentThread.Abort()
        End Try
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="ar"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jas]	7/12/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Private Sub recvCallback(ByVal ar As IAsyncResult)
        Dim bytes As Byte(), numbytes As Int32
        Try
            bytes = CType(ar.AsyncState, Byte())
            numbytes = sktThis.EndReceive(ar)
        Catch

        End Try
        'Added below to counter an IAsynResult bug
        If numbytes = 4094 Then
            numbytes = 0
            For Each bit As Byte In bytes
                If bit > 0 Then
                    numbytes += 1
                Else
                    Exit For
                End If
            Next
        End If
        If numbytes = 0 Then
            If Not sktThis Is Nothing Then
                sktThis.Shutdown(SocketShutdown.Both)
                sktThis.Close()
            End If
        Else
            'Problem here
            Dim rcvd As String = ASCII.GetString(bytes, 0, numbytes)
            'End problem
            Array.Clear(bytes, 0, bytes.Length)
            RaiseEvent DataReceived(rcvd)
            Console.Write("From host: {0}", rcvd)
            sktThis.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, _
                AddressOf recvCallback, bytes)
        End If
    End Sub
    Public Sub Send(ByVal data As String)
        If bDebug Then 'if debugging
            MsgBox("SENT:" + data)
            RaiseEvent DataReceived(dbgDataToSend(data))
        Else 'if not debugging
            Dim bytes() As Byte = ASCII.GetBytes(data)
            'Do Until sktThis.Connected : Loop
            Try
                sktThis.Send(bytes)
            Catch
                MsgBox("Communication to the server has been terminated. Please " _
                + "try again later.")
            End Try
        End If
    End Sub
    Public Sub Close()
        If Not sktThis Is Nothing Then
            If sktThis.Connected Then
                sktThis.Shutdown(SocketShutdown.Both)
            End If
            sktThis.Close()
            sktThis = Nothing
        End If
    End Sub
#End Region
#Region "Properties"
    Public ReadOnly Property Connected() As Boolean
        Get
            If Not bDebug Then
                Connected = sktThis.Connected()
            Else
                Connected = True
            End If
        End Get
    End Property
#End Region
    'Here lies the great Error timer :(
    'Private Sub tmrError_Tick(ByVal sender As Object, ByVal e As System.EventArgs)
    '    If Threading.Thread.CurrentThread.Name Is Nothing Then _
    '      Threading.Thread.CurrentThread.Name = "tmrError_Tick"
    '    Me.Connect()
    '    sender.GetType.GetProperty("Enabled").SetValue(sender, False, Nothing)
    '    Threading.Thread.CurrentThread.Abort()
    'End Sub
End Class
